home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_200 / 299_01 / mel.c < prev    next >
C/C++ Source or Header  |  1989-12-28  |  42KB  |  1,310 lines

  1. /*
  2. ---------------------------------------------------------------------------
  3. filename: mel.c
  4. author: g. m. crews
  5. creation date: 28-Jul-1988
  6. date of last revision: 19-Jul-1989
  7.  
  8. MEL is a comprehensive metalanguage input/output processor for engineering 
  9. analysis programs. its purposes are 1) to save the programmer development time
  10. when providing a user-friendly i/o interface, and 2) to establish a common
  11. protocol for interprogram messaging. these routines can be used by any
  12. analysis program for which a "dictionary" has been defined. see file
  13. "mel.doc" for more information.
  14.  
  15. note: these functions will normally return 0 if no error was encountered, 
  16. else a number (code) reflecting the type of error.
  17.  
  18. functions contained in this file:
  19.  
  20.     module #   name             global scope?
  21.     --------   -----------------------     -------------
  22.     1.0        meli_file         yes
  23.     1.1        end_of_data_in_file     no
  24.     1.2        meli             yes
  25.     1.2.1      compact_str         no
  26.     1.2.2      get_descrip_type      no
  27.     1.2.2.1    name_match         no
  28.     1.2.3      get_param_name         no
  29.     1.2.4      get_param_values      no
  30.     1.2.5      get_param_units         no
  31.     2.0        meli_descrip_type     yes
  32.     3.0        meli_num_params         yes
  33.     4.0        meli_param         yes
  34.     5.0        meli_data         yes
  35.     6.0        melo_init         yes
  36.     7.0        melo_data         yes
  37.     8.0        melo_file         yes
  38.     8.1        melo             yes
  39.     8.1.1      write_units_if_any     no
  40. ---------------------------------------------------------------------------
  41. */
  42.  
  43. #include <stdio.h>
  44. #include <string.h>
  45.  
  46. /*
  47. ---------------------------------------------------------------------------
  48. the following include file declares the dictionary that is to be used for
  49. MEL i/o.  note that this file will be unique for every program that uses
  50. this method of i/o.  (again, see file "mel.doc" for more information on how
  51. to further customize or modify this file.)
  52.  
  53. it also contains "public" (global) function prototyping and miscellaneous 
  54. data structures.
  55. ---------------------------------------------------------------------------
  56. */
  57.  
  58. #define MEL_INPUT
  59. #define MEL_OUTPUT
  60. #define MEL_PRIVATE
  61. #define MEL_INIT
  62. #include "mel.h"
  63.  
  64. /* "private" function prototyping:
  65.    (visible only to other routines in this file) */
  66.  
  67. static int end_of_data_in_file(int);
  68. static void compact_str(void);
  69. static int get_descrip_type(void);
  70. static int name_match(char *, char *, int);
  71. static int get_param_name(void);
  72. static int get_param_values(void);
  73. static int get_param_units(void);
  74. static void write_units_if_any(int);
  75.  
  76. /* "private" (local external) storage: */
  77.  
  78. static char descrip_str[MELI_MAX_DESCRIP_STR_LEN+1];
  79.     /* temp storage for descriptor string.
  80.        (read from file or given by MEL user). */
  81. static char *descrip_str_ptr;
  82.     /* current point of interest in above string. it is used by several 
  83.        routines that "translate" the string into MEL data structure. it points 
  84.        to the next character needing to be "translated". */
  85. static int curr_descrip_index;
  86.     /* what is descriptor's index into meli_descrip[] array? this allows
  87.        other local routines to know which parameters to check for. */
  88. static int datum_param_index;
  89.     /* where does this parameter's data go in meli_datum? */
  90.  
  91. /* the following variables are also local and deal with parameter handling: */
  92.  
  93. static int equals_sign_found_flag;
  94.     /* will there be a need to try and read a parameter value? */
  95. static int curr_param_index;
  96.     /* what is parameter's index into meli_descrip.param[] array? */
  97. static int param_name_found_flag;
  98.     /* as a safety measure, note when a parameter name has been found
  99.        for a descriptor (and do not let values without names follow). */
  100. static int left_parenthesis_found_flag;
  101.     /* will there be a need to try and read units? */
  102.  
  103. /*
  104. ---------------------------------------------------------------------------
  105. module 1.0
  106.  
  107. get a descriptor string from a file and put data into structure for easy
  108. access. that is:
  109.     read a descriptor from a file into "private" storage (descrip_str).
  110.     check for file read errors.
  111.     stop reading after semicolon encountered.
  112.     put a copy into meli_descriptor_string.
  113.     translate this string into MEL data structure (meli_datum).
  114.  
  115. algorithm synopsis: read characters from input stream until semi-
  116. colon (end-of-descriptor) is encountered, while putting them into
  117. private storage string.
  118. ---------------------------------------------------------------------------
  119. */
  120. int meli_file(
  121. FILE *input_file_handle)
  122. {
  123.     static int curr_line_num = 1;
  124.     /* assume that reading starts with the first line in a text file
  125.        and continues incrementally (one descriptor at a time). thus,
  126.        increment this variable everytime a newline character is
  127.        encountered. (that a descriptor may span several lines.) */
  128.  
  129.     int i;
  130.     /* loop counter. */
  131.  
  132.     int ch;
  133.     /* current char from input stream. */
  134.  
  135.     meli_datum.start_line = curr_line_num;
  136.     /* save the starting line number for this descriptor. */
  137.  
  138.     /* read from the input stream one character at a time: */
  139.  
  140.     for (i = 0; i < MELI_MAX_DESCRIP_STR_LEN; i++) {
  141.     ch = fgetc(input_file_handle);
  142.  
  143.     /* check for a file read error: */
  144.     if (ferror(input_file_handle)) {
  145.         mel_err.type = mel_read_err;
  146.         mel_err.start_line = meli_datum.start_line;
  147.         mel_err.end_line = curr_line_num;
  148.         strcpy(mel_err.msg, "MEL input file");
  149.         return mel_read_err;
  150.     };
  151.  
  152.     /* also error if unexpected end of file before semicolon: */
  153.     if ((ch == EOF) || (feof(input_file_handle))) {
  154.  
  155.         /* an exception is for the case of EOF right after a semicolon
  156.            (not counting any whitespace that might also have been read).
  157.            this is called the "end-of-data" error (which really isn't an
  158.            error at all, but a means of letting the caller know that no
  159.            more descriptors are in the file). */
  160.         if (end_of_data_in_file(i)) {
  161.         mel_err.type = mel_end_of_data_err;
  162.         mel_err.start_line = meli_datum.start_line;
  163.         mel_err.end_line = curr_line_num;
  164.         strcpy(mel_err.msg, "MEL input file");
  165.         return mel_end_of_data_err;
  166.         } else {
  167.         mel_err.type = mel_end_of_file_err;
  168.         mel_err.start_line = meli_datum.start_line;
  169.         mel_err.end_line = curr_line_num;
  170.         strcpy(mel_err.msg, "Missing semicolon, MEL input file");
  171.         return mel_end_of_file_err;
  172.         }
  173.     };
  174.  
  175.     if (ch == ';') break;
  176.         /* break the loop if a semicolon is encountered. */
  177.  
  178.     if (ch == '\n') curr_line_num++;
  179.         /* increment line number count for a new line */
  180.  
  181.     /* now add this character to the descriptor string and go get the
  182.        next character: */
  183.     descrip_str[i] = (char)ch;
  184.     }
  185.  
  186.     /* the descriptor has now been successfully read into the descriptor
  187.        string. time to tidy-up. */
  188.  
  189.     descrip_str[i++] = (char)ch;  /* tack on the semicolon */
  190.     descrip_str[i] = '\0';
  191.     meli_datum.end_line = curr_line_num;
  192.     strcpy(meli_descriptor_string, descrip_str);
  193.     /* make copy in case user wants to see it. */
  194.  
  195.     /* lastly, translate it (put data into meli_datum): */
  196.     return meli();
  197. }
  198.  
  199. /*
  200. ---------------------------------------------------------------------------
  201. module 1.1
  202.  
  203. has all the data been read from the MEL input file?
  204.  
  205. this routine is called when an end of file has been encountered. we must make
  206. sure that the user has not forgotten to append a semicolon on the last
  207. descriptor.  thus, it is an error condition if anything except whitespace
  208. has been read since the last semicolon (end-of-descriptor character).
  209.  
  210. return 1 if only whitespace has been read since last semicolon.
  211. return 0 if other (data) characters have been read since last semicolon.
  212. ---------------------------------------------------------------------------
  213. */
  214. static int end_of_data_in_file(
  215. int str_len)
  216. {
  217.     descrip_str[str_len] = '\0';
  218.     /* make string out of characters read since last semicolon. */
  219.  
  220.     compact_str();    /* remove whitespace from this string */
  221.  
  222.     if (strlen(descrip_str)) return 0;
  223.     else return 1;
  224.     /* if anything left over after compact